package com.lezhi.socialgram.service.sys.impl;

import com.lezhi.socialgram.enums.ResultEnum;
import com.lezhi.socialgram.exception.SocialGramException;
import com.lezhi.socialgram.mapper.sys.SMSVerifyCodeMapper;
import com.lezhi.socialgram.model.sys.VerifySMSCode;
import com.lezhi.socialgram.service.sys.SMSVeriService;
import com.lezhi.socialgram.util.*;
import com.taobao.api.ApiException;
import com.taobao.api.DefaultTaobaoClient;
import com.taobao.api.TaobaoClient;
import com.taobao.api.request.AlibabaAliqinFcSmsNumSendRequest;
import com.taobao.api.response.AlibabaAliqinFcSmsNumSendResponse;
import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.*;
import java.util.Date;
import java.util.List;

/**
 * Created by daizhen on 2017/3/30.
 */
@Service
public class SMSVeriServiceImpl implements SMSVeriService {

    private static final Logger logger = LoggerFactory.getLogger(SMSVeriServiceImpl.class);

    @Autowired
    SMSVerifyCodeMapper smsVerifyCodeMapper;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public Result getSMSVeriCode(String telNum) {
        try {
            Date todayStartDate = new Date(new Date().getTime() - 24 * 3600 * 1000);

            //验证短信24小时内不能超过7条。
            VerifySMSCode verifySMSCodeQO = new VerifySMSCode();
            verifySMSCodeQO.setTelNum(telNum);
            verifySMSCodeQO.setCreateTime(todayStartDate);

            List<VerifySMSCode> list = smsVerifyCodeMapper.getVerifySMSCodeList(verifySMSCodeQO);

            //超过7条就不发短信
            if (list != null && list.size() >= 7) {
                return ResultUtils.error(ResultEnum.REG_VERIFY_SMS_MAX_COUNT);
            } else {
                String veriCode = XUtil.genRandomNumPassword(4);

                //找到最近的一个验证码，看是否是半小时之内的。
                //如果是半小时之内的，那么就重发一下这个验证码。
                if (list.size() > 0) {
                    VerifySMSCode verifySMSCodeVO = list.get(0);
                    //判断最近的验证码是否是1分钟之内的，如果是1分钟之内的，那么就提示等下再获取
                    Date lastSendDate = verifySMSCodeVO.getCreateTime();
                    long gap = new Date().getTime() - lastSendDate.getTime();
                    if (gap < 60 * 1000) //1分钟之内
                    {
                        return ResultUtils.error(ResultEnum.REG_VERIFY_SMS_TOO_QUICK, (60 * 1000 - gap) / 1000 + "秒");
                    } else if (gap < 30 * 60 * 1000) {
                        veriCode = verifySMSCodeVO.getVeriCode();
                    }
                }


                int channel = getRandomSelectSMSChannel(-1);
//
                sendVeriCodeViaSMS(telNum, veriCode, channel);

                VerifySMSCode verifySMSCodeVO = new VerifySMSCode();
                verifySMSCodeVO.setHisId(stringRedisTemplate.opsForValue().increment(Param.SMS_VERIFY_CODE_SEQUENCE, 1));
                verifySMSCodeVO.setTable(TableUtils.getTableNameWithId(VerifySMSCode.class, Long.parseLong(telNum), 10));
                verifySMSCodeVO.setTelNum(telNum);
                verifySMSCodeVO.setHisId(stringRedisTemplate.opsForValue().increment(Param.SMS_VERIFY_CODE_SEQUENCE, 1));
                verifySMSCodeVO.setVeriCode(veriCode);
                verifySMSCodeVO.setStatus(VerifySMSCode.STATUS_SENT);
                verifySMSCodeVO.setChannel(channel);
                smsVerifyCodeMapper.addVerifySMSCode(verifySMSCodeVO);
                new SMSMakeupThread(telNum, smsVerifyCodeMapper, this,
                        Integer.parseInt(stringRedisTemplate.opsForValue().get(Param.SMS_VERIFY_RESEND_GAP)), stringRedisTemplate).start();
                return ResultUtils.success();
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new SocialGramException(ResultEnum.INTERNAL_ERROR);
        }
    }

    @Override
    public Result getSMSVeriCode(Long id) {
        try {
            String table = Param.T_USER_TABLE_PREFIX + XUtil.getTableNameIndexById(id);
            String telNum = smsVerifyCodeMapper.getTelNumByUserId(id, table);
            return getSMSVeriCode(telNum);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new SocialGramException(ResultEnum.INTERNAL_ERROR);
        }
    }

    @Override
    public Result verifySMSCode(String telNum, String veriCode) {
        try {
            //获得30分钟内的短信
            Date startDate = new Date(new Date().getTime() - 30 * 60 * 1000);

            VerifySMSCode verifySMSCodeQO = new VerifySMSCode();
            verifySMSCodeQO.setTable(TableUtils.getTableNameWithId(VerifySMSCode.class, Long.parseLong(telNum), 10));
            verifySMSCodeQO.setTelNum(telNum);
            verifySMSCodeQO.setCreateTime(startDate);
            List<VerifySMSCode> list = smsVerifyCodeMapper.getVerifySMSCodeList(verifySMSCodeQO);
            if (list != null && list.size() > 0) {
                VerifySMSCode veriSMS = list.get(0);

                //验证码验证正确
                if (veriCode.equalsIgnoreCase(veriSMS.getVeriCode())) {
                    //更新验证状态
                    smsVerifyCodeMapper.updateVerifySMSCodeStatus(veriSMS);

                    return ResultUtils.success();
                } else {
                    return ResultUtils.error(ResultEnum.REG_VERIFY_SMS_MISMATCH);
                }
            } else {
                return ResultUtils.error(ResultEnum.REG_VERIFY_SMS_MISMATCH);
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new SocialGramException(ResultEnum.INTERNAL_ERROR);
        }
    }

    public int getRandomSelectSMSChannel(int skipChannel) {
        int channel = 2;

        try {
            String channelsStr = stringRedisTemplate.opsForValue().get(Param.SMS_CHANNELS);
            String[] channels = channelsStr.split("/");
            int[] channelArr = new int[channels.length];
            int[] weightArr = new int[channels.length];
            int totalWeight = 0;
            for (int i = 0; i < channels.length; i++) {
                String[] channelDef = channels[i].split(":");
                String chanelIdStr = channelDef[0];
                String chanelWeightStr = channelDef[1];
                int channelId = Integer.parseInt(chanelIdStr);
                int channelWeight = Integer.parseInt(chanelWeightStr);

                if (channelId != skipChannel) {
                    totalWeight += channelWeight;
                    channelArr[i] = channelId;
                    weightArr[i] = totalWeight;
                }
            }

            //获得一个随机数
            int randomWeight = (int) (Math.random() * totalWeight);
            int selectIndex = 0;

            for (int i = 0; i < channels.length; i++) {
                if (randomWeight <= weightArr[i]) {
                    selectIndex = i;
                    break;
                }
            }

            channel = channelArr[selectIndex];
        } catch (Exception e) {
            channel = 2;
        }

        return channel;
    }

    /**
     * 通过短信发送验证码
     *
     * @param telNum
     * @param amount
     * @param tradeNo
     * @return
     */
    public void sendVeriCodeViaSMS(String telNum, String veriCode, int channel) {
        if (channel == 1) {
            sendSMSByJuhe(telNum, veriCode, "18486");
        } else if (channel == 2) {
            sendSMSByAliDayu(telNum, veriCode, "SMS_14241772"); //SMS_14241772
        } else if (channel == 3) {
            sendSMSByChuanglan(telNum, veriCode, "SMS_1");
        } else if (channel == 4) {
            sendSMSByHaoBo(telNum, veriCode, "SMS_1");
        }
    }

    /**
     * 通过创蓝发送短信
     *
     * @param telNum
     * @param code
     * @param templateId
     * @return
     */
    private void sendSMSByChuanglan(String telNum, String code, String templateId) {
        String url = "https://zapi.253.com/msg/";// 应用地址
        String account = "N1038031";// 账号
        String pswd = "7HqOUZcgze1892";// 密码
        String mobile = telNum;// 手机号码，多个号码使用","分割
        String msg = null;// 短信内容
        if (templateId.equalsIgnoreCase("SMS_1")) {
            msg = "【北瓜电话】您的验证码是" + code + "，30分钟内有效，请勿转发。";
        } else if (templateId.equalsIgnoreCase("SMS_2")) {
            msg = "【北瓜电话】您的登录帐号是注册手机号，登录密码是" + code + "，下载地址：http://mythcall.com，祝您生活愉快！";
        }
        boolean needstatus = false;// 是否需要状态报告，需要true，不需要false
        String extno = null;// 扩展码

        try {
            String returnString = batchSend(url, account, pswd, mobile, msg, needstatus, extno);
            System.out.println(returnString);
        } catch (Exception e) {

            logger.error("error:", e);
        }
    }

    /**
     * 通过阿里大鱼发送短信
     *
     * @param telNum
     * @param code
     * @param templateId "SMS_14231822"
     * @return
     */
    private void sendSMSByAliDayu(String telNum, String code, String templateId) {
        TaobaoClient client = new DefaultTaobaoClient("http://gw.api.taobao.com/router/rest", "23449299", "f9b8cc1950b79d5e85e10cae5f107c12");
        AlibabaAliqinFcSmsNumSendRequest req = new AlibabaAliqinFcSmsNumSendRequest();
        req.setExtend("");
        req.setSmsType("normal");
        req.setSmsFreeSignName("北瓜电话");
        req.setSmsParamString("{code:'" + code + "',product:'北瓜电话'}");
        req.setRecNum(telNum);
        req.setSmsTemplateCode(templateId);
        AlibabaAliqinFcSmsNumSendResponse rsp = null;
        try {
            rsp = client.execute(req);
            String respStr = rsp.getBody();
        } catch (ApiException e) {
            logger.error(e.getMessage(), e);
        }
    }


    /**
     * 通过juhe.com发短信
     *
     * @param telNum
     * @param code
     * @param templateId
     * @return
     */
    private void sendSMSByJuhe(String telNum, String code, String templateId) {
        String key = "28ec9ffac6255d20e0e70c90add9861b";
        String tplValue = "#code#=" + code;
        tplValue = URLEncoder.encode(tplValue);

        String str = sendPost("http://v.juhe.cn/sms/send",
                "key=" + key + "&mobile=" + telNum + "&tpl_id=" + templateId + "&tpl_value=" + tplValue + "&dtype=json");
    }

    /**
     * 通过昊博发短信
     *
     * @param phone
     * @param content
     * @return
     */
    public static void sendSMSByHaoBo(String phone, String code, String templateId) {
        String msg = null;// 短信内容
        if (templateId.equalsIgnoreCase("SMS_1")) {
            msg = "【北瓜电话】您的验证码是" + code + "，30分钟内有效，请勿转发。";
        } else if (templateId.equalsIgnoreCase("SMS_2")) {
            msg = "【北瓜电话】您的登录帐号是注册手机号，登录密码是" + code + "，下载地址：http://mythcall.com，祝您生活愉快！";
        }

        String t = null;
        try {
            t = haoboEncode(msg);
        } catch (UnsupportedEncodingException e1) {
            logger.error("error:", e1);
        }

        String url = "http://101.227.68.49:7891/mt?un=10690215&pw=leZHI2016" + "&da=" + phone + "&sm=" + t + "&dc=15&rd=1";
        String rs = "";
        try {
            URL urlclass = new URL(url);
            try {
                URLConnection connection = urlclass.openConnection();
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                StringBuffer sb = new StringBuffer();
                String line = null;
                while ((line = in.readLine()) != null) {
                    sb.append(line);
                }
                rs = sb.toString();
                System.out.println(rs);
                in.close();
            } catch (IOException e) {
                logger.error("error: ", e);
            }
        } catch (MalformedURLException e) {
            logger.error("error: ", e);
        }
    }

    public static String haoboEncode(String str) throws UnsupportedEncodingException {
        // 根据默认编码获取字节数组
        String hexString = "0123456789ABCDEF";
        byte[] bytes = str.getBytes("GB2312");
        StringBuilder sb = new StringBuilder(bytes.length * 2);
        // 将字节数组中每个字节拆解成2位16进制整数
        for (int i = 0; i < bytes.length; i++) {
            sb.append(hexString.charAt((bytes[i] & 0xf0) >> 4));
            sb.append(hexString.charAt((bytes[i] & 0x0f)));
        }
        return sb.toString();
    }

    public static String batchSend(String url, String account, String pswd, String mobile, String msg,
                                   boolean needstatus, String extno) throws Exception {
        HttpClient client = new HttpClient(new HttpClientParams(), new SimpleHttpConnectionManager(true));
        GetMethod method = new GetMethod();
        try {
            URI base = new URI(url, false);
            method.setURI(new URI(base, "HttpBatchSendSM", false));
            method.setQueryString(new NameValuePair[]{
                    new NameValuePair("account", account),
                    new NameValuePair("pswd", pswd),
                    new NameValuePair("mobile", mobile),
                    new NameValuePair("needstatus", String.valueOf(needstatus)),
                    new NameValuePair("msg", msg),
                    new NameValuePair("extno", extno),
            });
            int result = client.executeMethod(method);
            if (result == HttpStatus.SC_OK) {
                InputStream in = method.getResponseBodyAsStream();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int len = 0;
                while ((len = in.read(buffer)) != -1) {
                    baos.write(buffer, 0, len);
                }
                return URLDecoder.decode(baos.toString(), "UTF-8");
            } else {
                throw new Exception("HTTP ERROR Status: " + method.getStatusCode() + ":" + method.getStatusText());
            }
        } finally {
            method.releaseConnection();
        }
    }

    /**
     * 向指定url发送post方法的请求，
     *
     * @param url   发送请求的url
     * @param param 请求参数，请求参数应该是name1=value1&name2=value2的形式。
     * @result 所代表远程资源的相应结果
     */
    public String sendPost(String url, String param) {
        PrintWriter out = null;

        String result = "";
        URLConnection conn = null;
        OutputStream os = null;

        try {
            URL realUrl = new URL(url);
            conn = realUrl.openConnection();
            // 设置请求的请求参数
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0;Windows NT 5.1; SV1)");
            // 发送POST 请求必须设置的如下两行参数
            conn.setDoInput(true);
            conn.setDoOutput(true);
            // 获取URLConnection对象对应的输入流
            os = conn.getOutputStream();
            out = new PrintWriter(os);
            // 发送请求参数

            out.print(param);
            out.flush();
            out.close();
            os.close();


            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            String lines;
            StringBuffer sb = new StringBuffer("");
            while ((lines = reader.readLine()) != null) {
                if (lines.trim().length() > 0)
                    sb.append(lines);
            }
            result = sb.toString();

            reader.close();

        } catch (Exception e) {
            logger.error("sendPost, 发送post请求异常：", e);
        }
        return result;
    }


}
